home *** CD-ROM | disk | FTP | other *** search
- TITLE CALCULATE EQUATION
-
- ; AUTHOR Yuri Margolin
- ; http://mysoft.s5.com/
-
- ; DATE 24/01/01
- ; VERSION 1.12
-
- ; This program calculates
- ; linear equation: ax + b = 0
- ; The result is printed with
- ; floating point.
- ; For example: a = 7, b = 2
- ; x = -0.28571428....
-
- ; Directive to select
- ; "make EXE" by default when
- ; source file is compiled:
- #MAKE_EXE#
-
-
- DSEG SEGMENT 'DATA'
- CR EQU 13
- LF EQU 10
- NEW_LINE EQU 13, 10, '$'
- MESS0 DB 'Calculation of ax + b = 0', NEW_LINE
- MESS1 DB 'ENTER a (-32768..32767)!', NEW_LINE
- MESS2 DB LF, CR, 'ENTER b (-32768..32767)!', NEW_LINE
- MESS3 DB CR, LF, CR, LF, 'Data:', '$'
- MESS4 DB CR, LF, ' a = ', '$'
- MESS5 DB CR, LF, ' b = ', '$'
- MESS6 DB CR, LF, 'Result: ', CR, LF, ' x = ', '$'
- MESS7 DB CR, LF, CR, LF, 'NO SOLUTION!', NEW_LINE
- MESS8 DB CR, LF, CR, LF, 'INFINITE NUMBER OF SOLUTIONS!', NEW_LINE
- ERROR DB CR, LF, 'THE NUMBER IS OUT OF RANGE!', NEW_LINE
- TWICE_NL DB NEW_LINE, NEW_LINE
- make_minus DB ? ; used as a flag in procedures.
- a DW ?
- b DW ?
- ten DW 10 ; used as multiplier.
- four DW 4 ; used as divider.
- DSEG ENDS
-
- SSEG SEGMENT STACK 'STACK'
- DW 100h DUP(?)
- SSEG ENDS
-
- CSEG SEGMENT 'CODE'
-
- ;*******************************************************************
-
- START PROC FAR
-
- ; Store return address to OS:
- PUSH DS
- XOR AX, AX
- PUSH AX
-
- ; Set segment registers:
- MOV AX, DSEG
- MOV DS, AX
- MOV ES, AX
-
- ; Welcome message:
- LEA DX, MESS0
- CALL PUTS ; Display the message.
-
- ; Ask for 'a' :
- LEA DX, MESS1
- CALL PUTS ; Display the message.
- CALL SCAN_NUM ; Input the number into CX.
- MOV a, CX
-
- ; Ask for 'b' :
- LEA DX, MESS2
- CALL PUTS ; Display the message.
- CALL SCAN_NUM ; Input the number into CX.
- MOV b, CX
-
- ; Print the data:
- LEA DX, MESS3
- CALL PUTS
-
- LEA DX, MESS4
- CALL PUTS
- MOV AX, a
- CALL PRINT_NUM ; print AX.
-
- LEA DX, MESS5
- CALL PUTS
- MOV AX, b
- CALL PRINT_NUM ; print AX.
-
-
- ; Check data:
- CMP a, 0
- JNE soluble ; jumps when a<>0.
- CMP b, 0
- JNE no_solution ; jumps when a=0 AND b<>0.
- JMP infinite ; jumps when a=0 AND b=0.
- soluble:
-
- ; Calculate the solution:
- ; ax + b = 0 -> ax = -b -> x = -b/a
-
- NEG b
-
- MOV AX, b
-
- XOR DX, DX
-
- ; check the sign, make DX:AX negative if AX is negative:
- CMP AX, 0
- JNS not_singned
- NOT DX
- not_singned:
- MOV BX, a ; divider is in BX.
-
- ; '-b' is in DX:AX.
- ; 'a' is in BX.
-
- IDIV BX ; AX = DX:AX / BX (DX - remainder).
-
- ; 'x' is in AX.
- ; remainder is in DX.
-
- PUSH DX ; store the remainder.
-
- LEA DX, MESS6
- CALL PUTS
-
- POP DX
-
- ; print 'x' as float:
- ; AX - whole part
- ; DX - remainder
- ; BX - divider
- CALL PRINT_FLOAT
-
- JMP end_prog
- no_solution:
- LEA DX, MESS7
- CALL PUTS
- JMP end_prog
- infinite:
- LEA DX, MESS8
- CALL PUTS
- end_prog:
- LEA DX, TWICE_NL
- CALL PUTS
-
- RET
- START ENDP
-
- ;***************************************************************
-
- ; Prints number in AX and it's fraction in DX.
- ; used to print remainder of 'DIV/IDIV BX'.
- ; AX - whole part.
- ; DX - remainder.
- ; BX - the divider that was used to get the remainder from divident.
- PRINT_FLOAT PROC NEAR
- PUSH CX
- PUSH DX
-
- ; because the remainder takes the sign of divident
- ; its sign should be inverted when divider is negative
- ; (-) / (-) = (+)
- ; (+) / (-) = (-)
- CMP BX, 0
- JNS div_not_signed
- NEG DX ; make remainder positive.
- div_not_signed:
-
- ; PRINT_NUM procedure does not print the '-'
- ; when the whole part is '0' (even if the remainder is
- ; negative) this code fixes it:
- CMP AX, 0
- JNE checked ; AX<>0
- CMP DX, 0
- JNS checked ; AX=0 and DX>=0
- PUSH DX
- MOV DL, '-'
- CALL WRITE_CHAR ; print '-'
- POP DX
- checked:
-
- ; print whole part:
- CALL PRINT_NUM
-
- ; if remainder=0, then no need to print it:
- CMP DX, 0
- JE done
-
- PUSH DX
- ; print dot after the number:
- MOV DL, '.'
- CALL WRITE_CHAR
- POP DX
-
- ; print digits after the dot:
- MOV CX, 15 ; max digits after the dot.
- CALL PRINT_FRACTION
- done:
- POP DX
- POP CX
- RET
- PRINT_FLOAT ENDP
-
- ;***************************************************************
-
- ; Prints DX as fraction of division by BX.
- ; DX - remainder.
- ; BX - divider.
- ; CX - maximum number of digits after the dot.
- PRINT_FRACTION PROC NEAR
- PUSH AX
- PUSH DX
- next_fraction:
- ; check if all digits are already printed:
- CMP CX, 0
- JZ end_rem
- DEC CX ; decrease digit counter.
-
- ; when remainder is '0' no need to continue:
- CMP DX, 0
- JE end_rem
-
- MOV AX, DX
- XOR DX, DX
- CMP AX, 0
- JNS not_sig1
- NOT DX
- not_sig1:
-
- IMUL ten ; DX:AX = AX * 10
-
- IDIV BX ; AX = DX:AX / BX (DX - remainder)
-
- PUSH DX ; store remainder.
- MOV DX, AX
- CMP DX, 0
- JNS not_sig2
- NEG DX
- not_sig2:
- ADD DL, 30h ; convert to ASCII code.
- CALL WRITE_CHAR ; print DL.
- POP DX
-
- JMP next_fraction
- end_rem:
- POP DX
- POP AX
- RET
- PRINT_FRACTION ENDP
-
- ;***************************************************************
-
- ; This procedure prints number in AX,
- ; used with PRINT_NUMX to print "0" and sign.
- ; this procedure also stores the original AX,
- ; that is modified by PRINT_NUMX.
- PRINT_NUM PROC NEAR
- PUSH DX
- PUSH AX
-
- CMP AX, 0
- JNZ not_zero
-
- MOV DL, '0'
- CALL WRITE_CHAR
- JMP printed
-
- not_zero:
- ; the check SIGN of AX,
- ; make absolute if it's negative:
- CMP AX, 0
- JNS positive
- NEG AX
-
- MOV DL, '-'
- CALL WRITE_CHAR
- positive:
- CALL PRINT_NUMX
- printed:
- POP AX
- POP DX
- RET
- PRINT_NUM ENDP
-
- ;***************************************************************
-
- ; Prints out a number in AX (not just a single digit)
- ; allowed values from 1 to 65535 (FFFF)
- ; (result of /10000 should be the left digit or "0").
- ; modifies AX (after the procedure AX=0)
- PRINT_NUMX PROC NEAR
- PUSH BX
- PUSH CX
- PUSH DX
-
- ; flag to prevent printing zeros before number:
- MOV CX, 1
-
- MOV BX, 10000 ; 2710h - divider.
-
- ; Check if AX is zero, if zero go to end_show
- CMP AX, 0
- JZ end_show
-
- begin_print:
-
- ; check divider (if zero go to end_show):
- CMP BX,0
- JZ end_show
-
- ; avoid printing zeros before number:
- CMP CX, 0
- JE calc
- ; if AX<BX then result of DIV will be zero:
- CMP AX, BX
- JB skip
- calc:
- XOR CX, CX ; set flag.
-
- XOR DX, DX
- DIV BX ; AX = DX:AX / BX (DX=remainder).
-
- ; print last digit
- ; AH is always ZERO, so it's ignored
- PUSH DX
- MOV DL, AL
- ADD DL, 30h ; convert to ASCII code.
- CALL WRITE_CHAR
- POP DX
-
- MOV AX, DX ; get remainder from last div.
-
- skip:
- ; calculate BX=BX/10
- PUSH AX
- XOR DX, DX
- MOV AX, BX
- DIV ten ; AX = DX:AX / 10 (DX=remainder).
- MOV BX, AX
- POP AX
-
- JMP begin_print
-
- end_show:
-
- POP DX
- POP CX
- POP BX
- RET
- PRINT_NUMX ENDP
-
- ;***************************************************************
-
- ; Displays the message (DX-address)
- PUTS PROC NEAR
- PUSH AX
- MOV AH, 09h
- INT 21h
- POP AX
- RET
- PUTS ENDP
-
- ;*******************************************************************
-
- ; Reads char from the keyboard into AL
- ; (MODIFIES AX!!!)
- READ_CHAR PROC NEAR
- MOV AH, 01h
- INT 21h
- RET
- READ_CHAR ENDP
-
- ;***************************************************************
-
- ; Gets the multi-digit SIGNED number from the keyboard,
- ; Result is stored in CX
- SCAN_NUM PROC NEAR
- PUSH DX
- PUSH AX
-
- XOR CX, CX
-
- ; reset flag:
- MOV make_minus, 0
-
- next_digit:
-
- CALL READ_CHAR
-
- ; check for MINUS:
- CMP AL, '-'
- JE set_minus
-
- ; check for ENTER key:
- CMP AL, CR
- JE stop_input
-
- ; multiply CX by 10 (first time the result is zero)
- PUSH AX
- MOV AX, CX
- MUL ten ; DX:AX = AX*10
- MOV CX, AX
- POP AX
-
- ; check if the number is too big
- ; (result should be 16 bits)
- CMP DX, 0
- JNE out_of_range
-
- ; convert from ASCII code:
- SUB AL, 30h
-
- ; add AL to CX:
- XOR AH, AH
- ADD CX, AX
- JC out_of_range ; jump if the number is too big.
-
- JMP next_digit
-
- set_minus:
- MOV make_minus, 1
- JMP next_digit
-
- out_of_range:
- LEA DX, ERROR
- CALL PUTS
-
- stop_input:
- ; check flag:
- CMP make_minus, 0
- JE not_minus
- NEG CX
- not_minus:
-
- POP AX
- POP DX
- RET
- SCAN_NUM ENDP
-
- ;***************************************************************
-
- ; Prints out single char (ascii code should be in DL)
- WRITE_CHAR PROC NEAR
- PUSH AX
- MOV AH, 02h
- INT 21h
- POP AX
- RET
- WRITE_CHAR ENDP
-
- ;***************************************************************
-
- CSEG ENDS
- END START
-